/*******************************************************************************
 * Copyright (c) 2000, 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package com.architexa.org.eclipse.gef.ui.parts;

import com.architexa.org.eclipse.draw2d.FigureCanvas;
import com.architexa.org.eclipse.draw2d.IFigure;
import com.architexa.org.eclipse.draw2d.Viewport;
import com.architexa.org.eclipse.draw2d.geometry.Dimension;
import com.architexa.org.eclipse.draw2d.geometry.Point;
import com.architexa.org.eclipse.draw2d.geometry.Rectangle;
import com.architexa.org.eclipse.gef.EditPart;
import com.architexa.org.eclipse.gef.GraphicalEditPart;

import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;



/**
 * A Graphical Viewer implementation which uses a {@link com.architexa.org.eclipse.draw2d.FigureCanvas}
 * for native scrolling.  Because the scrolling is handled natively, the root editpart
 * should not contain a {@link com.architexa.org.eclipse.draw2d.ScrollPane} figure.  Do not use root
 * editparts which provide scrollpane figures, such as <code>GraphicalRootEditPart</code>.
 * <P>
 * The RootEditPart for a ScrollingGraphicalViewer may contain a Viewport.  If it does,
 * that viewport will be set as the FigureCanvas' viewport.  FigureCanvas has certain
 * requirements on the viewport figure, see {@link FigureCanvas#setViewport(Viewport)}.
 * @author hudsonr
 */
public class ScrollingGraphicalViewer
	extends GraphicalViewerImpl
{

/**
 * Constructs a ScrollingGraphicalViewer;
 */
public ScrollingGraphicalViewer() { }

/**
 * @see com.architexa.org.eclipse.gef.EditPartViewer#createControl(org.eclipse.swt.widgets.Composite)
 */
public final Control createControl(Composite parent) {
	FigureCanvas canvas = new FigureCanvas(parent, getLightweightSystem());
	super.setControl(canvas);
	installRootFigure();
	return canvas;
}

/**
 * Convenience method which types the control as a <code>FigureCanvas</code>. This method
 * returns <code>null</code> whenever the control is null.
 * @return <code>null</code> or the Control as a FigureCanvas
 */
protected FigureCanvas getFigureCanvas() {
	return (FigureCanvas)getControl();
}

/**
 * If the figure is a viewport, set the canvas' viewport, otherwise, set its contents.
 */
private void installRootFigure() {
	if (getFigureCanvas() == null)
		return;
	if (rootFigure instanceof Viewport)
		getFigureCanvas().setViewport((Viewport)rootFigure);
	else
		getFigureCanvas().setContents(rootFigure);
}

/**
 * Extends the superclass implementation to scroll the native Canvas control after the
 * super's implementation has completed.
 * @see com.architexa.org.eclipse.gef.EditPartViewer#reveal(com.architexa.org.eclipse.gef.EditPart)
 */
public void reveal(EditPart part) {
	super.reveal(part);
	Viewport port = getFigureCanvas().getViewport();
	IFigure target = ((GraphicalEditPart)part).getFigure();
	Rectangle exposeRegion = target.getBounds().getCopy();
	target = target.getParent();
	while (target != null && target != port) {
		target.translateToParent(exposeRegion);
		target = target.getParent();
	}
	exposeRegion.expand(5, 5);
	
	Dimension viewportSize = port.getClientArea().getSize();

	Point topLeft = exposeRegion.getTopLeft();
	Point bottomRight = exposeRegion.getBottomRight().translate(viewportSize.getNegated());
	Point finalLocation = new Point();
	if (viewportSize.width < exposeRegion.width)
		finalLocation.x = Math.min(bottomRight.x, Math.max(topLeft.x, port.getViewLocation().x));
	else
		finalLocation.x = Math.min(topLeft.x, Math.max(bottomRight.x, port.getViewLocation().x));

	if (viewportSize.height < exposeRegion.height)
		finalLocation.y = Math.min(bottomRight.y, Math.max(topLeft.y, port.getViewLocation().y));
	else
		finalLocation.y = Math.min(topLeft.y, Math.max(bottomRight.y, port.getViewLocation().y));

	
	getFigureCanvas().scrollSmoothTo(finalLocation.x, finalLocation.y);	
}

/**
 * @see GraphicalViewerImpl#setRootFigure(IFigure)
 */
protected void setRootFigure(IFigure figure) {
	rootFigure = figure;
	installRootFigure();
}

}
